﻿#include "libcomm.h"

#define CHECK_BUFFER_OVERLAP(ptr)	{	\
	if(ptr >= m_buffer && ptr < m_buffer+m_size) {\
		LOGERR("!!! memory overlap: %p <= %p < %p !!!",m_buffer,ptr,m_buffer+m_size); \
		MYLIB_ASSERT(!"memory overlap!"); \
	}	\
}

void* Buffer::malloc(size_t size)
{
	return ::malloc(size);
}

void* Buffer::calloc(size_t num, size_t size)
{
	return ::calloc(num,size);
}

void* Buffer::realloc(void* ptr, size_t size)
{
	return ::realloc(ptr,size);
}

void Buffer::free(void* ptr)
{
	::free(ptr);
}


Buffer::Buffer(size_t size):m_buffer(NULL),m_size(0),m_capacity(0)
{
	if (size > 0)
	{
		this->resize(size);
	}
}

Buffer::Buffer(const void* ptr, size_t size):m_buffer(NULL),m_size(0), m_capacity(0)
{
	if(NULL != ptr && size > 0)
	{
		this->resize(size, false);
		::memcpy(m_buffer,ptr, size);
	}
}


Buffer::Buffer(const Buffer& rhs):m_buffer(NULL),m_size(0), m_capacity(0)
{
	const char* mem = rhs.get();
	size_t size = rhs.size();
	if(NULL != mem && size > 0)
	{
		this->resize(size, false);
		::memcpy(m_buffer,mem,size);
	}
}

Buffer& Buffer::operator=(const Buffer& rhs)
{
	const char* mem = rhs.get();
	size_t size = rhs.size();
	if (mem != m_buffer) // may be self = self.
	{
		this->resize(size, false);
		::memcpy(m_buffer, mem, size);
	}
	return *this;
}

Buffer::~Buffer(void)
{
	this->release();
}

void Buffer::release()
{
	if(NULL != m_buffer)
	{
		Buffer::free(m_buffer);
		m_buffer = NULL;
		m_size = 0;
		m_capacity = 0;
	}
}

Buffer::operator char*()
{
	return this->get();
}

Buffer::operator const char*() const
{
	return this->get();
}

char* Buffer::get()
{
	if (0 == m_size)
		return NULL;
	return m_buffer;
}

const char* Buffer::get() const
{
	if (0 == m_size)
		return NULL;
	return m_buffer;
}

size_t Buffer::size() const
{
	return m_size;
}

size_t Buffer::capacity() const
{
	return m_capacity;
}

Buffer& Buffer::memset(int val)
{
	if (NULL != m_buffer && 0 < m_size)
		::memset(m_buffer, val, m_size);
	return *this;
}

Buffer& Buffer::reserve(size_t size, bool zero_memory)
{
	MYLIB_ASSERT(m_size <= m_capacity);
	if (size > m_capacity)
	{
		m_capacity = size;
		m_buffer = (char*)Buffer::realloc(m_buffer, size);
		MYLIB_ASSERT_NOTNULL(m_buffer);
		if (zero_memory)
			::memset(m_buffer + m_size, 0, size - m_size);
	}
	return *this;
}

Buffer& Buffer::resize(size_t size, bool zero_memory)
{
	if (size > m_capacity)
	{
		reserve(size, false);
	}
	if (zero_memory)
	{
		if (size > m_size)
			::memset(m_buffer + m_size, 0, size - m_size);
		else
			::memset(m_buffer + size, 0, m_size - size);
	}
	m_size = size;
	return *this;
}

Buffer& Buffer::consume(size_t size)
{
	MYLIB_ASSERT(size >= 0 && size <= m_size);
	if(size != m_size)
		::memmove(m_buffer, m_buffer + size , m_size-size);
	m_size -= size;
	return *this;
}

Buffer& Buffer::append(const void* ptr, int size)
{
	if (NULL != ptr && 0 < size)
	{
		size_t old_size = this->size();
		CHECK_BUFFER_OVERLAP(ptr);
		this->resize(old_size + size, false);
		memcpy(m_buffer + old_size, ptr, size);
	}
	return *this;
}

Buffer& Buffer::append(const Buffer& rhs)
{
	return append(rhs.get(),rhs.size());
}


////////////////////////////////////////////////////////////////////////// StringList

typedef std::vector<String> InnerStringVector;
#define STRINGLISTINST ((InnerStringVector*)m_list)
#define STRINGLISTINSTCOPY(rhs)	(*((InnerStringVector*)m_list) = *((InnerStringVector*)rhs.m_list))

StringList::StringList():m_list(NULL)
{
	m_list = new InnerStringVector();
	MYLIB_ASSERT_NOTNULL(m_list);
}

StringList::StringList(const StringList& rhs):m_list(NULL)
{
	m_list = new InnerStringVector();
	MYLIB_ASSERT_NOTNULL(m_list);
	STRINGLISTINSTCOPY(rhs);
}

StringList& StringList::operator=(const StringList& rhs)
{
	if(m_list != rhs.m_list)
	{
		STRINGLISTINSTCOPY(rhs);
	}
	return *this;
}

StringList::~StringList()
{
	if(NULL != m_list)
	{
		delete STRINGLISTINST;
		m_list = NULL;
	}
}

int StringList::count() const
{
	return STRINGLISTINST->size();
}

String& StringList::get(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	return STRINGLISTINST->at(index);
}

const String& StringList::get(int index) const
{
	MYLIB_ASSERT(index>=0 && index<count());
	return STRINGLISTINST->at(index);
}

String& StringList::operator[](int index)
{
	return get(index);
}

const String& StringList::operator[](int index) const
{
	return get(index);
}

StringList& StringList::append(const String& inst)
{
	STRINGLISTINST->push_back(inst);
	return *this;
}

StringList& StringList::insert(int index, const String& inst)
{		
	MYLIB_ASSERT(index>=0 && index<=count());
	InnerStringVector::iterator itor = STRINGLISTINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	STRINGLISTINST->insert(itor,inst);
	return *this;
}	

StringList& StringList::remove(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	InnerStringVector::iterator itor = STRINGLISTINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	STRINGLISTINST->erase(itor);
	return *this;
}

StringList& StringList::clear()
{
	STRINGLISTINST->clear();
	return *this;
}

StringList& StringList::operator<<(const String& inst)
{
	return append(inst);
}

String StringList::join(const char* seperators) const
{
	String str;
	int count = this->count();
	for (int i=0;i<count;i++)
	{
		const String& item = this->get(i);
		if(i != 0)
			str << seperators;
		str << item;
	}
	return str;
}


////////////////////////////////////////////////////////////////////////// String
String String::Empty = "";

inline bool __IsEmptyChar(char c)
{
	char empty[] = " \t\n\r";
	char* pos = empty;
	while(0 != pos[0])
	{
		if(pos[0] == c)
			return true;
		++pos;
	}
	return false;
}

String::String(int length) : Buffer(length + 1)
{}

String::String(const char* src, int len) :
	Buffer(src, src ? (len? len:(String::strlen(src) + 1)) : 0)
{}

const char* String::operator*() const
{ return get();}

char& String::operator[](int index)
{
	char* buffer = this->get();
	int size = this->size();
	MYLIB_ASSERT(index >= 0 && index < size && NULL != buffer);
	return buffer[index];
}

const char& String::operator[](int index) const
{
	const char* buffer = this->get();
	int size = this->size();
	MYLIB_ASSERT(index >= 0 && index < size && NULL != buffer);
	return buffer[index];
}

bool String::null() const
{
	const char* buffer = this->get();
	int size = this->size();
	if(NULL == buffer || 0 == size)
		return true;
	return false;
}

bool String::empty() const
{
	if(!this->null())
	{
		int length = this->length();
		const char* cursor = this->get();
		for (int i=0;i<length;i++)
		{
			if(__IsEmptyChar(cursor[i]))
				continue;
			return false;
		}
	}
	return true;
}

int String::length() const
{
	const char* buffer = this->get();
	int size = this->size();
	if (size > 0)
	{
		int zero_count = 0;
		for (int i = size - 1; i >= 0; i--)
		{
			if (buffer[i] == 0)
			{
				zero_count++;
				continue;
			}
			break;
		}
		size -= zero_count;
	}
	return size;
}

bool String::equal(const String& src_, bool ignorecase) const
{
	const char* src = src_.get();
	const char* dst = this->get();
	int src_len = src_.length();
	int dst_len = this->length();

	if(NULL == dst || NULL == src)
	{
		return (NULL == dst && NULL == src);
	}

	if (src_len != dst_len)
		return false;

	for (int i = 0; i < src_len; i++)
	{
		char ch_src = src[i];
		char ch_dst = dst[i];
		if (ignorecase)
		{
			ch_src = ::tolower(ch_src);
			ch_dst = ::tolower(ch_dst);
		}

		if (ch_src != ch_dst)
			return false;
	}

	return true;
}

String& String::append(const String& src_)
{
	const char* src = src_.get();
	int src_size = src_.size();
	int dst_len = this->length();
	if (NULL != src)
	{
		size_t new_size = dst_len + src_size;
		this->resize(new_size, false);
		char* dst = this->get();
		memcpy(dst + dst_len, src, src_size);
	}
	return *this;
}

String& String::operator+=(const String& src)
{
	return this->append(src);
}

String& String::operator<<(const String& src)
{
	return this->append(src);
}

String String::operator+(const String& src) const
{
	String tmp;
	int len1 = this->length();
	int len2 = src.length();
	tmp.resize(len1 + len2 + 1, false);
	char* dst = tmp.get();
	memcpy(dst, this->get(), len1);
	memcpy(dst + len1, src.get(), len2);
	dst[len1 + len2] = 0;
	return tmp;
}

bool String::operator==(const String& src) const
{
	return this->equal(src);
}

bool String::operator!=(const String& src) const
{
	return !this->equal(src);
}

bool String::operator==(const char* src) const
{
	return this->equal(src);
}

bool String::operator!=(const char* src) const
{
	return !this->equal(src);
}

int String::toint() const
{
	if(this->null())
		return 0;
	return atoi(this->get());
}

long long String::tolong() const
{
	if(this->null())
		return 0;
#ifdef COMM_MSVC
	return _atoi64(this->get());
#else
	return atoll(this->get());
#endif
}

double String::todouble() const
{
	if(this->null())
		return 0.0f;
	return atof(this->get());
}

String& String::tolower()
{
	if(!this->null())
	{
		char* pos = this->get();
		while(pos[0] != 0)
		{
			pos[0] = ::tolower(pos[0]);
			++pos;
		}
	}
	return *this;
}

String& String::toupper()
{
	if(!this->null())
	{
		char* pos = this->get();
		while(pos[0] != 0)
		{
			pos[0] = ::toupper(pos[0]);
			++pos;
		}
	}
	return *this;
}

String& String::reverse()
{
	if(!this->null())
	{
		char* s = this->get();
		char* h = s;  
		char* t = s;
		char ch;
		while(*t++){};
		t--;    
		t--;   
		while(h < t)
		{
			ch = *h;
			*h++ = *t;  
			*t-- = ch; 
		}
	}
	return *this;
}

String& String::trimleft()
{
	if(!this->null())
	{
		String tmp = this->get();
		char* cursor = tmp;
		int length = tmp.length();
		int i;
		for (i=0;i<length;i++)
		{
			if(__IsEmptyChar(cursor[i]))
			{
				continue;
			}
			break;
		}
		if(i != 0)
			*this = cursor + i;
	}
	return *this;
}

String& String::trimright()
{
	if(!this->null())
	{
		String tmp = this->get();
		char* cursor = tmp;
		int length = tmp.length();
		int i;
		for(i=length-1;i>=0;i--)
		{
			if(__IsEmptyChar(cursor[i]))
			{
				cursor[i] = 0;
				continue;
			}
			break;
		}
		if(i != length-1)
			*this = cursor;
	}
	return *this;
}

String& String::trim()
{
	return this->trimleft().trimright();
}

String& String::replace(const String& substr_, const String& newstr_, bool replaceall)
{
	char* start = this->get();
	const char* substr = substr_.get();
	const char* newstr = newstr_.get();
	if (NULL != start && NULL != substr && NULL != newstr)
	{
		String tmp;
		char* pos = NULL;
		int substr_len = substr_.length();
		while (NULL != (pos = strstr(start, substr)))
		{
			pos[0] = 0;
			tmp += start;
			tmp += newstr;
			start = pos + substr_len;
			if (!replaceall)
				break;
		}
		tmp += start;
		*this = tmp;
	}
	return *this;
}

String& String::remove(const String& substr, bool removeall)
{
	return this->replace(substr, String::Empty, removeall);
}

bool String::find(const String& str) const
{
	if (this->null() || str.null())
		return false;
	return (NULL != strstr(this->get(), str));
}

bool String::startwith(const String& str) const
{
	if (this->null() || str.null())
		return false;
	return (strstr(this->get(), str) == this->get());
}

bool String::endwith(const String& str) const
{
	String tmp_src = *this;
	String tmp_dst = str;
	tmp_src.reverse();
	tmp_dst.reverse();
	return tmp_src.startwith(tmp_dst);
}

StringList String::split(const String& seperators) const
{
	StringList list;
	if (!this->null() && !seperators.null())
	{
		String tmp = *this;
		char* pToken = NULL;
#ifdef COMM_MSVC
		pToken = ::strtok(tmp, seperators);
		while (NULL != pToken)
		{
			list.append(pToken);
			pToken = strtok(NULL, seperators);
		}
#else
		char* pSave = NULL;
		pToken = ::strtok_r(tmp, seperators, &pSave);
		while (NULL != pToken)
		{
			list.append(pToken);
			pToken = ::strtok_r(NULL, seperators, &pSave);
		}
#endif
	}
	return list;
}


String& String::strcat(const String& src)
{
	if (!this->null() && !src.null())
	{
		char* buffer = this->get();
		int size = this->size();
		int length = this->length();
		::strncpy(buffer + length, src, size - 1 - length);
		buffer[size - 1] = 0;
	}
	return *this;
}

String& String::vsprintf(const char* format, va_list args)
{
	if (!this->null() && NULL != format)
	{
		char* buffer = this->get();
		int size = this->size();
		CHECK_BUFFER_OVERLAP(format);
		::vsnprintf(buffer, size - 1, format, args);
		buffer[size - 1] = 0;
	}
	return *this;
}

String& String::sprintf(const char* format, ...)
{
	va_list args;
	va_start(args, format);
	this->vsprintf(format, args);
	va_end(args);
	return *this;
}

////////////////////////////////////////////////////////////////////////// Static

// strdup has bugs in windows linked in different CRT.
char* String::strdup(const char* src)
{
	if (NULL == src)
		return NULL;
	int length = String::strlen(src);
	char *dest = (char*)Buffer::malloc(length + 1);
	if (NULL == dest)
		return NULL;
	::memcpy(dest, src, length);
	dest[length] = 0;
	return dest;
}

int String::strlen(const char* src)
{
	int len = 0;
	if (NULL != src)
	{
		len = ::strlen(src);
	}
	return len;
}

bool String::equal(const char* src, const char* str, bool ignorecase)
{
	return String(src).equal(str,ignorecase);
}

String String::join(const char* src, const char* str)
{
	return String(src).append(str);
}

String String::tolower(const char* src)
{
	return String(src).tolower();
}

String String::toupper(const char* src)
{
	return String(src).toupper();
}

String String::reverse(const char* src)
{
	return String(src).reverse();
}

String String::trimleft(const char* src)
{
	return String(src).trimleft();
}

String String::trimright(const char* src)
{
	return String(src).trimright();
}

String String::trim(const char* src)
{
	return String(src).trim();
}

bool String::find(const char* src, const char* str)
{
	return String(src).find(str);
}

bool String::startwith(const char* src, const char* str)
{
	return String(src).startwith(str);
}

bool String::endwith(const char* src, const char* str)
{
	return String(src).endwith(str);
}

StringList String::split(const char* src, const char* seperators)
{
	return String(src).split(seperators);
}


String String::format(const char* format, ...)
{
	String dest(COMM_STRING_DEFAULT_LENGTH);
	va_list args;
	va_start(args, format);
	dest.vsprintf(format, args);
	va_end(args);
	return dest;
}

String String::format(int size, const char* format, ...)
{
	String dest(size);
	va_list args;
	va_start(args, format);
	dest.vsprintf(format, args);
	va_end(args);
	return dest;
}

String String::from(unsigned short num)
{
	return String::format(32, "%hu", num);
}

String String::from(unsigned int num)
{
	return String::format(32, "%u", num);
}

String String::from(unsigned long num)
{
	return String::format(32, "%lu", num);
}

String String::from(unsigned long long num)
{
	return String::format(32, "%llu", num);
}

String String::from(short num)
{
	return String::format(32, "%hd", num);
}

String String::from(int num)
{
	return String::format(32, "%d", num);
}

String String::from(long num)
{
	return String::format(32, "%ld", num);
}

String String::from(long long num)
{
	return String::format(32, "%lld", num);
}

String String::from(float num)
{
	return String::format(32,"%f", num);
}

String String::from(double num)
{
	return String::format(32, "%lf", num);
}
